package main

import (
	"fmt"
	"sync"
)

/**
【1】WaitGroup的作用:
		WaitGroup用于等待一组线程的结束。
		父线程调用Add方法来设定应等待的线程的数量。
		每个被等待的线程在结束时应调用Done方法。
		同时主线程里可以调用Wait方法阻塞至所有线程结束。
		---》解决主线程在子协程结束后自动结束
*/

var wg sync.WaitGroup
var totalNum int = 0
var totalNum2 int = 0

func main() {
	//test()

	// 多个协程操作同一个数据：
	test2()
	//test3()
}

/*
*
有一个机制:确保:一个协程在执行逻辑的时候另外的协程不执行----》锁的机制---》加入互斥锁
sync.Mutex
*/
var lock sync.Mutex

func test3() {
	wg.Add(2)
	go add2()
	go sub2()
	wg.Wait()
	fmt.Println("totalNum2== ", totalNum2)
}

func add2() {
	defer wg.Done()
	for i := 0; i < 100000; i++ {
		lock.Lock() // 加锁
		totalNum2++
		lock.Unlock() //解锁
	}
}

func sub2() {
	defer wg.Done()
	for i := 0; i < 100000; i++ {
		lock.Lock()
		totalNum2--
		lock.Unlock()
	}
}

// 多个协程操作同一个数据：
// 正常来说add()和sub()的次数是一样的最终结果应该是0，实际结果却不是
// 解决方法见下面的test3()
func test2() {
	wg.Add(2)
	go add()
	go sub()
	wg.Wait()
	fmt.Println("totalNum== ", totalNum)
}

func test() {
	// 启动10个协程
	for i := 0; i < 10; i++ {
		wg.Add(1)        // 协程开始的时候加1操作
		go func(i int) { // 开启协程
			fmt.Println("协程执行== ", i)
			wg.Done() // 协程执行完成减1操作
		}(i)
	}
	wg.Wait() // 主线程等待所有协程执行完成
}

func add() {
	defer wg.Done()
	for i := 0; i < 100000; i++ {
		totalNum++
	}
}

func sub() {
	defer wg.Done()
	for i := 0; i < 100000; i++ {
		totalNum--
	}
}
